package com.neborosoft.FlyingDog.android.playing;

import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.View;
import android.widget.*;
import com.neborosoft.FlyingDog.R;
import com.neborosoft.FlyingDog.android.FlyingDog;
import com.neborosoft.FlyingDog.android.MyActivity;
import com.neborosoft.FlyingDog.android.gui.adapters.listview.OnItemSelected;
import com.neborosoft.FlyingDog.android.gui.adapters.listview.SongsPlayListAdapter;
import com.neborosoft.FlyingDog.android.gui.dialogs.MainWindow;
import com.neborosoft.FlyingDog.logic.database.AudioDataManager;
import com.neborosoft.FlyingDog.logic.database.content.identified.Audio;
import com.neborosoft.android.events.EventManager;
import com.neborosoft.android.events.HistoryManager;
import com.neborosoft.android.threading.AndroidOnHostThreadExecutor;
import com.neborosoft.lib.handlers.OnHardwareBackPressed;
import com.neborosoft.lib.threading.AbstractAsyncTask;
import com.neborosoft.lib.threading.OnHostThreadExecutor;
import com.neborosoft.lib.threading.Threading;

import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.Executor;

/**
 * Created with IntelliJ IDEA.
 * User: CM
 * Date: 27.09.12
 * Time: 23:07
 * To change this template use File | Settings | File Templates.
 */
public class Player{
    private static final Executor EXECUTOR = Threading.getSharedExecutor();
    private static final OnHostThreadExecutor ON_HOST_THREAD_EXECUTOR = new AndroidOnHostThreadExecutor();

    private Activity activeActivity;

    private HistoryManager historyManager = HistoryManager.getInstance();
    private Context context;

    private SeekBar playListSeekBar;
    private TextView playListDurationStart,playListDurationEnd;

    private ViewFlipper windowSwitcher;
    private int mainWindowIndex;
    private int playListWindowIndex;
    private MainWindow mainWindow;

    private MediaPlayer player;

    private SeekBarAndDurationViewsUpdater seekBarAndDurationViewsUpdater;

    private Audio currentAudio;

    private ImageButton playButton;

    private boolean setDataSourceUrl(String url){
        player.reset();

        Uri uri = Uri.parse(url);
        try {
            player.setDataSource(context, uri);
        } catch (IOException e) {
            return false;
        }

        player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mediaPlayer) {
                player.start();
            }
        });
        player.prepareAsync();

        return true;
    }

    private void onTrySetDataSourceUrlFailed(){

    }

    private void trySetDataSourceUrl(final Iterator<String> urlIterator){
        player.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                trySetDataSourceUrl(urlIterator);
                return true;
            }
        });

        if(urlIterator.hasNext()){
            if(!setDataSourceUrl(urlIterator.next())) {
                trySetDataSourceUrl(urlIterator);
            } else {
                player.setOnErrorListener(new OnPlayerError());
            }
        } else {
            onTrySetDataSourceUrlFailed();
        }
    }

    private AbstractAsyncTask urlsGettingTask
            = new AbstractAsyncTask<Void,Iterable<String>>(ON_HOST_THREAD_EXECUTOR)
    {
        @Override
        protected Iterable<String> doInBackground(Void params) {
            return AudioDataManager.getInstance().getSuggestedAudioUrls(currentAudio);
        }

        @Override
        protected void onPostExecute(Iterable<String> urls) {
            trySetDataSourceUrl(urls.iterator());
        }
    };

    private void setCurrentAudio(final Audio audio, final boolean play) {
        this.currentAudio = audio;

        player.setOnErrorListener(new OnPlayerError());

        player.reset();

        String url = audio.getUrl();
        if (url != null) {
            setDataSourceUrl(url);
        } else {
            urlsGettingTask.execute(EXECUTOR);
        }

        if(seekBarAndDurationViewsUpdater != null){
            seekBarAndDurationViewsUpdater.reset(audio.getDuration());
        }

        setPlayListSeekBarAndDurationsVisibility(true);
    }

    private class OnPlayButtonClick implements Button.OnClickListener{
        @Override
        public void onClick(View view) {
            if(!player.isPlaying()){
                player.start();
            }
            else{
                player.pause();
            }
        }
    }

    private class OnPlayerError implements MediaPlayer.OnErrorListener{
        @Override
        public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
            return true;
        }
    }

    private void switchPlayingView(){
        if(windowSwitcher.getDisplayedChild() == playListWindowIndex){
            windowSwitcher.setDisplayedChild(mainWindowIndex);
        }
        else{
            windowSwitcher.setDisplayedChild(playListWindowIndex);
        }
        initMainWindow();
    }

    private class OnSwitchViewButtonClick implements Button.OnClickListener{
        @Override
        public void onClick(View view) {
            if(!SongsPlayListAdapter.isSongSelected()){
                return;
            }

            initMainWindow();
            switchPlayingView();
            historyManager.pushHardwareBackPressedListener(new OnHardwareBackPressed() {
                @Override
                public void onBack() {
                    switchPlayingView();
                }
            });
        }
    }

    private void playNextTrack(){
        SongsPlayListAdapter.selectNextTrack();
    }

    private void playPrevTrack(){
        SongsPlayListAdapter.selectPrevTrack();
    }

    private class OnCompletePlayTrack implements MediaPlayer.OnCompletionListener{
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            playNextTrack();
        }
    }

    private class OnNextButtonClick implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            playNextTrack();
        }
    }

    private class OnPrevButtonClick implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            playPrevTrack();
        }
    }

    private class OnTrackSelectedListener implements OnItemSelected<Audio> {
        @Override
        public void onItemSelected(Audio element, int position, boolean selectionIndexChanged) {
            if(selectionIndexChanged){
                setCurrentAudio(element, true);
                if(mainWindow != null){
                    mainWindow.notifyAdapterDataSetChanged();
                    mainWindow.setCurrentSongIndex(position);
                }
            }
            else if(playButton != null) {
                playButton.performClick();
            }
        }
    }

    private void setPlayListSeekBarAndDurationsVisibility(boolean visibility){
        if(playListSeekBar == null){
            return;
        }

        int value = View.GONE;
        if(visibility){
            value = View.VISIBLE;
        }
        playListSeekBar.setVisibility(value);
        playListDurationEnd.setVisibility(value);
        playListDurationStart.setVisibility(value);
    }

    private void initMainWindow(){
        if(mainWindow != null){
            return;
        }

        mainWindow = new MainWindow(activeActivity) {
            @Override
            public void onNextSong() {
                playNextTrack();
            }

            @Override
            public void onPrevSong() {
                playPrevTrack();
            }
        };

        SongsPlayListAdapter songsPlayListAdapter = SongsPlayListAdapter.getSelectedSongsAdapter();
        Iterable<Audio> tracks = songsPlayListAdapter.getElements();
        int selectedSongIndex = songsPlayListAdapter.getCurrentSelectedIndex();
        mainWindow.setCurrentSongIndex(selectedSongIndex);
    }

    public void onActivityCreated(final Activity activity){
        activeActivity = activity;

        windowSwitcher = (ViewFlipper)activity.findViewById(R.id.windowSwitcher);
        mainWindowIndex = windowSwitcher.indexOfChild(activity.findViewById(R.id.mainLayout));
        playListWindowIndex = windowSwitcher.indexOfChild(activity.findViewById(R.id.playListLayout));
        windowSwitcher.setDisplayedChild(playListWindowIndex);

        seekBarAndDurationViewsUpdater = new SeekBarAndDurationViewsUpdater(player);

        ImageButton button = (ImageButton)activity.findViewById(R.id.playButton);
        playButton = button;
        button.setOnClickListener(new OnPlayButtonClick());
        button = (ImageButton)activity.findViewById(R.id.nextButton);
        button.setOnClickListener(new OnNextButtonClick());
        button = (ImageButton)activity.findViewById(R.id.prevButton);
        button.setOnClickListener(new OnPrevButtonClick());
        button = (ImageButton)activity.findViewById(R.id.switchViewButton);
        button.setOnClickListener(new OnSwitchViewButtonClick());

        playListSeekBar = (SeekBar)activity.findViewById(R.id.seekBarListElement);
        playListDurationStart = (TextView)activity.findViewById(R.id.listElementDurationFirst);
        playListDurationEnd = (TextView)activity.findViewById(R.id.listElementDurationSecond);
        setPlayListSeekBarAndDurationsVisibility(false);
        seekBarAndDurationViewsUpdater.addSeekBarAndDurationViews(
                playListSeekBar,
                playListDurationStart,
                playListDurationEnd);
        EventManager.getInstance().addRenderingEvent(seekBarAndDurationViewsUpdater);

        button = (ImageButton)activity.findViewById(R.id.menuButton);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                activity.openOptionsMenu();
            }
        });
    }

    public void onActivityDestroyed(){
        EventManager.getInstance().removeEvent(seekBarAndDurationViewsUpdater);
        activeActivity = null;
    }

    public Player(Context context){
        this.context = context;

        player = new MediaPlayer();
        player.setOnCompletionListener(new OnCompletePlayTrack());
        player.setOnErrorListener(new OnPlayerError());

        SongsPlayListAdapter.setOnItemSelectionChangedListener(new OnTrackSelectedListener());
    }
}
